using System;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using Sensor.SerialPorts;
using Sensor.SerialPorts.Enums;
using Sensor.UI.Models;
using Sensor.UI.Processors;

namespace Sensor.UI.ViewModels;

/// <summary>
/// 串口会话视图模型，负责管理串口连接、数据接收和事件处理
/// </summary>
public partial class SerialPortSessionViewModel : ViewModelBase
{
    #region 私有字段

    /// <summary>
    /// 串口管理器，负责底层串口通信
    /// </summary>
    private readonly SerialPortManager _serialPortManager = new(true);

    /// <summary>
    /// 文本协议分包器，负责解析传感器数据帧
    /// </summary>
    private readonly TextProtocolFrameSplitter _textProtocolFrameSplitter = new();

    #endregion

    #region 公共属性

    #region 串口配置属性

    /// <summary>
    /// 串口名称
    /// </summary>
    [ObservableProperty]
    private string _port = string.Empty;

    /// <summary>
    /// 波特率，默认为115200
    /// </summary>
    [ObservableProperty]
    private int _baudRate = 115200;

    /// <summary>
    /// 校验位，默认为无校验
    /// </summary>
    [ObservableProperty]
    private ParityBit _parityBit = ParityBit.None;

    /// <summary>
    /// 停止位，默认为1位停止位
    /// </summary>
    [ObservableProperty]
    private StopBit _stopBit = StopBit.One;

    /// <summary>
    /// 数据位，默认为8位数据位
    /// </summary>
    [ObservableProperty]
    private int _dataBit = 8;

    #endregion

    #region 状态属性

    /// <summary>
    /// 获取串口是否已打开
    /// </summary>
    [ObservableProperty]
    private bool _isOpen;

    #endregion

    #endregion

    #region 事件

    #region 事件定义

    /// <summary>
    /// 接收到有效传感器数据帧时触发
    /// </summary>
    /// <param name="frameText">原始帧文本</param>
    /// <param name="sensorInfo">解析后的传感器信息</param>
    public event Action<string, SensorInfo>? ValidFrameReceived;

    /// <summary>
    /// 串口通信发生错误时触发
    /// </summary>
    /// <param name="errorMessage">错误描述信息</param>
    public event Action<string>? ErrorOccurred;

    #endregion

    #endregion

    #region 公共方法

    /// <summary>
    /// 异步打开串口连接
    /// 如果串口已打开，则先关闭再重新打开
    /// </summary>
    /// <param name="cancellationToken">用于取消操作的取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    /// <exception cref="InvalidOperationException">当串口配置无效时抛出</exception>
    public async Task OpenAsync(CancellationToken cancellationToken = default)
    {
        // 如果串口已打开，先关闭
        if (IsOpen)
        {
            await CloseAsync(cancellationToken).ConfigureAwait(false);
        }

        // 检查是否已请求取消
        cancellationToken.ThrowIfCancellationRequested();

        // 清空分包器缓冲区，确保数据解析的完整性
        _textProtocolFrameSplitter.ClearBuffer();

        // 订阅分包器的事件
        _textProtocolFrameSplitter.ValidFrameReceived += OnValidFrameReceived;

        // 打开串口连接
        await _serialPortManager.OpenAsync(Port, BaudRate, ParityBit, StopBit, DataBit, cancellationToken).ConfigureAwait(false);

        // 订阅串口管理器的事件
        _serialPortManager.ErrorOccurred += OnErrorOccurred;
        _serialPortManager.BinaryFrameReceived += OnBinaryFrameReceived;

        // 更新状态
        IsOpen = _serialPortManager.IsOpen;
    }

    /// <summary>
    /// 异步关闭串口连接
    /// </summary>
    /// <param name="cancellationToken">用于取消操作的取消令牌</param>
    /// <returns>表示异步操作的任务</returns>
    public async Task CloseAsync(CancellationToken cancellationToken = default)
    {
        if (!IsOpen) return;
        try
        {
            // 检查是否已请求取消
            cancellationToken.ThrowIfCancellationRequested();

            // 取消订阅事件，避免内存泄漏
            _serialPortManager.ErrorOccurred -= OnErrorOccurred;
            _serialPortManager.BinaryFrameReceived -= OnBinaryFrameReceived;
            _textProtocolFrameSplitter.ValidFrameReceived -= OnValidFrameReceived;

            // 关闭串口连接
           await _serialPortManager.CloseAsync(cancellationToken).ConfigureAwait(false);

            // 更新状态
            IsOpen = _serialPortManager.IsOpen;
        }
        catch (Exception ex)
        {
            ErrorOccurred?.Invoke($"关闭串口时发生错误: {ex.Message}");
        }
    }

    #endregion

    #region 私有方法

    #region 事件处理方法

    /// <summary>
    /// 处理接收到的有效数据帧
    /// 将分包器解析后的传感器信息转发给外部订阅者
    /// </summary>
    /// <param name="frameText">原始帧文本</param>
    /// <param name="sensorInfo">解析后的传感器信息</param>
    private void OnValidFrameReceived(string frameText, SensorInfo sensorInfo)
    {
        ArgumentNullException.ThrowIfNull(frameText);
        ArgumentNullException.ThrowIfNull(sensorInfo);
        
        ValidFrameReceived?.Invoke(frameText, sensorInfo);
    }

    /// <summary>
    /// 处理接收到的原始二进制数据
    /// 将原始数据传递给分包器进行解析
    /// </summary>
    /// <param name="buffer">接收到的字节数据</param>
    private void OnBinaryFrameReceived(byte[] buffer)
    {
        ArgumentNullException.ThrowIfNull(buffer);
        
        try
        {
            // 将原始数据传递给文本协议分包器进行解析
            _textProtocolFrameSplitter.ProcessReceivedData(buffer);
        }
        catch (Exception ex)
        {
            ErrorOccurred?.Invoke($"数据处理错误: {ex.Message}");
        }
    }

    /// <summary>
    /// 处理串口通信错误
    /// 将底层错误信息转发给外部订阅者
    /// </summary>
    /// <param name="errorMessage">错误描述信息</param>
    private void OnErrorOccurred(string errorMessage)
    {
        ArgumentNullException.ThrowIfNull(errorMessage);
        
        ErrorOccurred?.Invoke(errorMessage);
    }

    #endregion

    #endregion

    #region 资源释放

    /// <summary>
    /// 释放资源
    /// 确保串口连接正确关闭，避免资源泄漏
    /// </summary>
    /// <param name="disposing">指示是否正在释放托管资源</param>
    protected override void Dispose(bool disposing)
    {
        if (!disposing)
        {
            base.Dispose(disposing);
            return;
        }

        // 确保串口连接已关闭
        if (!IsOpen)
        {
            // 即使串口未打开，仍需要释放托管资源
            ReleaseManagedResources();
            base.Dispose(disposing);
            return;
        }

        try
        {
            // 在Dispose中使用同步方式关闭串口，避免异步操作
            _serialPortManager.ErrorOccurred -= OnErrorOccurred;
            _serialPortManager.BinaryFrameReceived -= OnBinaryFrameReceived;
            _textProtocolFrameSplitter.ValidFrameReceived -= OnValidFrameReceived;
            
            // 使用同步方式等待异步操作完成
            _serialPortManager.CloseAsync(CancellationToken.None).Wait();
            IsOpen = _serialPortManager.IsOpen;
        }
        catch
        {
            // 忽略关闭时的异常
        }
        finally
        {
            // 释放托管资源
            ReleaseManagedResources();
        }

        base.Dispose(disposing);
    }

    /// <summary>
    /// 释放托管资源
    /// </summary>
    private void ReleaseManagedResources()
    {
        try
        {
            // 释放串口管理器资源
            if (_serialPortManager is IDisposable serialPortDisposable)
            {
                serialPortDisposable.Dispose();
            }

            // 释放文本协议分包器资源
            if (_textProtocolFrameSplitter is IDisposable splitterDisposable)
            {
                splitterDisposable.Dispose();
            }
        }
        catch
        {
            // 忽略释放时的异常
        }
    }

    #endregion
}
